const Router = require('koa-router');
const router = new Router();
const {setBillNo, updateAssQty, saveHistPrice, saveContactSales, saveContactGoods, billCanEdit, toAccounted,
    setInvoiceGoods
} = require("./base");
const tools = require("../../tools/tool");
const {db, Op, QueryTypes} = require("../../models/db");
const tool = require("../../tools/tool");
let clickTime = {}
// 设置应付结余表
router.post('/bill/save', async ctx => {
    let currentUnix = tools.dayjs().valueOf()
    let tenantId = ctx.user.tenantId
    if (clickTime[tenantId]) {
        if (currentUnix - clickTime[tenantId].lastTime < 500) {
            return ctx.err('不要频繁点击')
        }
        clickTime[tenantId] = {
            lastTime: currentUnix
        }
    }
    else {
        clickTime[tenantId] = {
            lastTime: currentUnix
        }
    }
    let transType = ctx.request.body.transType
    let billDate = ctx.request.body.billDate
    if (!billDate) return ctx.err('请选择开票日期');
    if (tools.dayjs(billDate).diff(tools.getDay(), 'days') > 0) {
        return ctx.err('票据日期不能超过今天')
    }
    await billCanEdit(billDate, tenantId)
    switch (transType) {
        case 190001: // 凭证
            return await saveCard(ctx)
        case 150501: // 采购
        case 150502: // 采退
        case 150601: // 销售
        case 150602: // 销退
        case 150603: // 换货
        case 150706: // 其他入库
        case 150806: {
            let bm = tools.dayjs(billDate).month()
            let cm = tools.dayjs(tools.getDay()).month()
            if (Math.abs(bm - cm) > 2) {
                // return ctx.err('禁止跨3个月录出入库数据')
            }
            return await savePurSale(ctx)
        }
        case 153001: // 收款
        case 153101: // 付款
            return await saveReceiptPayment(ctx)
        case 153401: // 其他收入
        case 153402: // 其他支出
            return await saveSrZc(ctx)
        case 153403: // 预收商品
            return await saveYsg(ctx)
        case 160001: // 转账单
            return await saveTrans(ctx)
        case 153404: // 其他应收
        case 153405: // 其他应付
            return await saveYsYf(ctx)
        case 153406: // 预付
        case 153407: // 预收
            return await saveYsf(ctx)
        default:
            return ctx.err('未知票据类型')
    }
})
router.post('/bill/saveSaleBack', async ctx => {
    let user = ctx.user
    let tenantId = user.tenantId;
    let body = ctx.request.body
    let data = ctx.request.body.data
    let uname = user.name;
    let uid = user.id;
    let ctime = tool.getTime()
    let tuiBillDate = data.tuiBillDate;
    let tuiRemark = data.tuiRemark ? data.tuiRemark : '';
    let invoiceData = data; // 上传的数据
    let invList = invoiceData.infos; // 商品列表
    if (!tuiBillDate) return ctx.err('请选择票据日期');
    // 如果原票据是草稿 则审核
    let invoiceOld = await db.models['invoice'].findOne({
        where: {
            tenantId,
            id: invoiceData.id,
        }
    })
    if (invoiceOld.billState === 'del') return ctx.err('原始原票据已删除');
    // 如果是草稿，检测库存，并审核
    try {
        let invoice = null
        if (invList.length > 0) {
            await billCanEdit(tuiBillDate, tenantId)
            let amount = 0
            let invoiceInfos = [];
            for (let i = 0; i < invList.length; i++) {
                let it = invList[i]
                it.calNum = it.spec
                let price = tool.xe.toNumber(it.price)
                let qty = tool.xe.toNumber(it.qty)
                if (price === 0) {
                    return ctx.err('金额不能为 0');
                }
                if (qty === 0) {
                    return ctx.err('数量不能为 0');
                }
                let subAmount = tool.multiply(price, qty)
                let inv = {
                    invId: it.invId,
                    calNum: it.spec,
                    locationId: it.locationId,
                    sendId: 0,
                    invName: it.invName,
                    spec: it.spec,
                    locationName: it.locationName,
                    unit: it.unit,
                    qty: it.qty,
                    price: it.price,
                    amount: subAmount,
                    remark: ''
                }
                amount = tool.add(amount, subAmount)
                invoiceInfos.push(inv);
            }
            if (amount === 0) {
                return ctx.err('金额不能为 0');
            }
            invoice = {
                id: null,
                billNo: '',
                billDate: tuiBillDate,
                cbyName: uname,
                cby: uid,
                billState: 'draft',
                billType: 'SALE',
                transType: 150602,
                transTypeName: '销售退货单',
                buId: invoiceData.buId,
                salesId: invoiceData.salesId,
                salesName: invoiceData.salesName,
                deliverIds: invoiceData.deliverIds,
                deliverNames: invoiceData.deliverNames,
                totalAmount: amount,
                disAmount: 0,
                rpAmount: 0,
                accName: '',
                accId: 0,
                arrears: amount,
                remark: tuiRemark,
                subRemark: '',
                ter: body.ter,
                invoiceInfos: invoiceInfos,
                menuId: invoiceData.menuId
            }
        }

        await db.transaction(async () => {
            // 原票据审核
            if (invoiceOld.billState === 'draft') {
                // invoiceOld.billDate = invoiceData.tuiBillDate;
                if (invoiceData.salesId !== invoiceOld.salesId) {
                    invoiceOld.salesId = invoiceData.salesId ? invoiceData.salesId : null;
                }
                if (invoiceData.deliverIds !== invoiceOld.deliverIds) {
                    if (!tool.xe.isArray(invoiceData.deliverIds)) {
                        invoiceOld.deliverIds = invoiceData.deliverIds ? invoiceData.deliverIds : null;
                        invoiceOld.deliverNames = invoiceData.deliverNames ? invoiceData.deliverNames : '';
                    }
                }
                if (invoiceData.remark !== invoiceOld.remark) {
                    invoiceOld.remark = invoiceData.remark ? invoiceData.remark : '';
                }
                invoice.billDate = invoiceData.billDate
                await invoiceOld.save()
                await toAccounted(ctx, [invoiceOld.id])
            }

            // 有关联退货
            if (invoice) {
                invoice.byScan = 1;
                //
                ctx.request.body = {
                    ...invoice,
                    infos: invList
                }

                let ret = await savePurSale(ctx)

                if (ret.stat) {
                    await toAccounted(ctx, [ret.data.id])
                }
                else {
                    throw Error(ret.msg)
                }
                // // 关联退货关系表
                // await db.models['invoiceBack'].create({
                //     tenantId,
                //     oldIid: invoiceData.id,
                //     iid: ret.data.id,
                //     cby: uid,
                //     ctime,
                //     isDel: 0
                // })
            }
        })
        return ctx.suc('审核成功');
    }
    catch (e) {
        return ctx.err(e);
    }
})
router.post('/bill/saveScanReceipt', async ctx => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let tenantId = user.tenantId;
        // 先审核收款列表中的草稿
        if(!body.receipts || body.receipts.length === 0) return ctx.err('没有要收款的票据')
        let invoice = await db.query(`select * from v_main where tenantId=${tenantId} and id=${body.receipts[0].billId} `,{type: QueryTypes.SELECT, plain: true})
        // 1、如果有关联退货 生生成退货单据，2、加入抵扣票据
        let uid = user.id;
        let uname = user.name;
        let ctime = tool.getTime()
        let billDate = body.billDate;
        if (!body.doId) {
            return ctx.err('请选择收款经办人');
        }
        // 如果有退货，先保存退货，再把退货加入抵扣列表
        let invoiceBack = null // 关联退货数据
        let backInfo = body.back;
        let tuList = backInfo.list.filter(row => {
            return row.invId && tool.xe.toNumber(row.qty) !== 0
        });
        if (tuList.length > 0) {
            let invoiceInfos = [];
            let amount = 0;
            for (let i = 0; i < tuList.length; i++) {
                let it = tuList[i]
                let price = tool.xe.toNumber(it.price)
                let qty = tool.xe.toNumber(it.qty)
                if (price === 0) {
                    return ctx.err('金额不能为 0');
                }
                if (qty === 0) {
                    return ctx.err('数量不能为 0');
                }
                let subAmount = tool.multiply(price, qty)
                let inv = {
                    invId: it.invId,
                    calNum: it.spec,
                    locationId: it.locationId,
                    sendId: 0,
                    invName: it.invName,
                    spec: it.spec,
                    locationName: it.locationName,
                    unit: it.unit,
                    qty: it.qty,
                    price: it.price,
                    amount: subAmount,
                    remark: ''
                }
                amount = tool.add(amount, subAmount)
                invoiceInfos.push(inv);
            }
            if (amount === 0) {
                return ctx.err('退货金额不能为 0');
            }
            invoiceBack = {
                id: null,
                billDate: backInfo.billDate,
                cbyName: uname,
                cby: uid,
                billState: 'draft',
                billType: 'SALE',
                transType: 150602,
                transTypeName: '销售退货单',
                buId: invoice.buId,
                salesId: invoice.salesId,
                salesName: invoice.salesName,
                deliverIds: invoice.deliverIds,
                deliverNames: invoice.deliverNames,
                totalAmount: amount,
                amount: amount,
                disAmount: 0,
                rpAmount: 0,
                accName: '',
                accId: 0,
                arrears: amount,
                remark: backInfo.remark,
                subRemark: '',
                ter: 'pc',
                byScan: 1,
                infos: invoiceInfos,
            }
        }
        let receipts = []


        await db.transaction(async () => {
            // 收款业务票据中有草稿，先审核草稿
            for (let i = 0; i < body.receipts.length; i++) {
                let row = body.receipts[i]
                if(row.billState === 'draft') {
                    await toAccounted(ctx, [row.billId])
                }
                receipts.push({
                    billDate: row.billDate,
                    billId: row.billId,
                    hxAmount: '',
                    leftAmount: row.leftAmount,
                    nowCheck: row.nowCheck,
                    remark: '',
                    srcBillNo: row.billNo,
                    srcBillType: 'SALE',
                    srcTransType: row.transType,
                    srcTransTypeName: row.transTypeName,
                    yhAmount: row.yhAmount,
                    arrears: row.leftAmount,
                    totalAmount: row.totalAmount,
                    ysAmount: 0
                })
            }

            // 保存退货数据
            if (invoiceBack) {
                ctx.request.body = invoiceBack
                // 保存
                let retBack = await savePurSale(ctx)
                //  新增关联退货单据写入成功，把其加入收款列表
                if (retBack.stat) {
                    await toAccounted(ctx, [retBack.data.id])
                }
                else {
                    throw new Error(retBack.msg)
                }

                let it = await db.query(`select *,(arrearsReal-(hxAmount+yhAmount)) leftAmount  from v_main_withhx where tenantId=${tenantId} and id=${retBack.data.id} `,{type: QueryTypes.SELECT, plain: true})
                let row = {
                    billDate: it.billDate,
                    billId: it.id,
                    hxAmount: '',
                    leftAmount: it.leftAmount,
                    nowCheck: it.arrearsReal,
                    remark: '',
                    srcBillNo: it.billNo,
                    srcBillType: it.billType,
                    srcTransType: it.transType,
                    srcTransTypeName: it.transTypeName,
                    yhAmount: tool.xe.sum(tuList, 'yhAmount'),
                    arrears: it.arrearsReal,
                    totalAmount: it.totalAmountReal,
                    ysAmount: 0
                }
                receipts.push(row);
            }
            let dis = tools.xe.sum(receipts, 'yhAmount')
            let total = tools.xe.add(body.accAmount, body.accAmount1)
            // 收款票据
            let invoiceReceipt = {
                id: null,
                billState: 'draft',
                billDate: billDate,
                accId: body.accId,
                accName: body.accName,
                accAmount: body.accAmount,
                accId1: body.accId1 ? body.accId1 : 0,
                accName1: body.accName1 ? body.accName1 : '',
                accAmount1: body.accAmount1 ? body.accAmount1 : 0,
                buId: invoice.buId,
                buName: invoice.buName,
                cby: uid,
                cbyName: uname,
                doId: body.doId,
                doName: body.doName,
                menuId: body.menuId,
                ter: 'pc',
                billType: 'RECEIPT',
                transType: 153001,
                transTypeName: '收款单',
                remark: '',
                byScan: 1,
                disAmount: dis,
                amount: total,
                rpAmount: total,
                totalAmount: total,
                infos: receipts
            }

            ctx.request.body = invoiceReceipt
            delete invoiceReceipt.id
            let retBack = await saveReceiptPayment(ctx)
            if (retBack.stat) {
                await toAccounted(ctx, [retBack.data.id])
            }
            else {
                throw new Error(retBack.msg)
            }
        })
        return ctx.suc('收款成功');
    } catch (e) {
        return ctx.err(e);
    }
})
// 配送机上退货
router.post('/bill/saveBack', async ctx => {
    let tenantId = ctx.user.tenantId
    let transType = 150602;
    let transTypeName = '销售退货单';
    let invoices = ctx.request.body.data;
    if(invoices.length === 0) return ctx.err('没有列表')

    await db.transaction(async () => {
        for (let i = 0; i < invoices.length; i++) {
            let list = invoices[i].infos.filter(row => {
                return row.invId && row.qty
            })
            if(list.length === 0) return ctx.err('没有商品列表')
            list.map(row => {
                if(row.unit === row.unit1) row.calNum = row.spec
                if(row.unit === row.unit2) row.calNum = 1
                delete row._RID
            })
            let oldBillId =  invoices[i].billId
            let invoice = {
                buId: invoices[i].buId,
                buName: invoices[i].buName,
                billDate: tools.getDay(),
                transType: transType,
                transTypeName: transTypeName,
                billType: 'SALE',
                totalAmount: tool.xe.sum(list, 'amount'),
                amount: tool.xe.sum(list, 'amount'),
                arrears: tool.xe.sum(list, 'amount'),
                orgin: 'ps',
                infos: list
            }
            ctx.request.body = invoice
            let ret = await savePurSale(ctx)
            if(ret.stat && ret.data.id) {
                if(oldBillId) {
                    let back = {
                        tenantId,
                        oldIid: oldBillId,
                        iid: ret.data.id,
                        ctime: tool.getTime()
                    }
                    await db.models['invoiceBack'].create(back)
                }
                // 记账
                await toAccounted(ctx, [ret.data.id])
            }
        }
    })
    let model = db.models['invoiceBackBak'].build()
    model.tenantId = tenantId
    model.billDate = tools.getDay()
    model.content = JSON.stringify(invoices)
    await model.save()
    return ctx.suc('保存成功', model.id)
})
// 保存零售
router.post('/bill/saveLs', async ctx => {
    let tenantId = ctx.user.tenantId
    let transType = ctx.request.body.transType
    let billDate = ctx.request.body.billDate
    if (!billDate) return ctx.err('请选择开票日期');
    if (tools.dayjs(billDate).diff(tools.getDay(), 'days') > 0) {
        return ctx.err('票据日期不能超过今天')
    }
    await billCanEdit(billDate, tenantId)
    if(transType === 150601) {
        let bm = tools.dayjs(billDate).month()
        let cm = tools.dayjs(tools.getDay()).month()
        if (Math.abs(bm - cm) > 2) {
            // return ctx.err('禁止跨3个月录出入库数据')
        }
        return await savePurSale(ctx)
    }
})
// 保存兑付
router.post('/bill/saveDf', async ctx => {
    let user = ctx.user
    let body = ctx.request.body
    let tenantId = user.tenantId;
    let id = body.id;
    let dfType = body.dfType?body.dfType:'';
    if(!dfType) return ctx.err('请选择兑付类型')
    let accId = body.accId?body.accId:0;
    if(!id) return ctx.err('请先计算兑付再保存')
    let model = await db.models['sendDf'].findOne({
        where: {
            tenantId,
            id
        }
    })
    if(!model) return ctx.err('未找到数据')
    model.dfType = dfType
    if(dfType === '转其他收入') {
        if(!accId) {
            return ctx.err('请选择兑付收款账户')
        }
        model.accId = accId
    }
    let resql = `
        with bills as (
            select a.tenantId,a.invId,b.name invName,b.brandName,
                   a.spec,a.unit,a.sendPrice,sum(a.dz) dz,sum(a.zz) zz,sum(a.cl) cl,sum(a.xl) xl,sum(a.ht) ht,sum(a.ky) ky,sum(a.zy) zy,sum(a.qty) qty
            from send_df_detail a inner join v_goods b on a.tenantId=b.tenantId and a.invId=b.id
            where sendDfId=${id}
            GROUP BY a.tenantId, a.invId, b.name, b.brandName, a.spec, a.unit, a.sendPrice
        ) select sum((qty/spec)*sendPrice) amount from bills
    `
    let amount = await db.query(resql,{type: QueryTypes.SELECT, plain: true})
    let sub = await db.models['category'].findOne({
        where: {
            tenantId,
            name: '政策兑付收入'
        }
    })
    if(!sub) return ctx.err('没有政策兑付收入 科目')
    await db.transaction(async () => {
        model.amount = amount ? amount.amount:0
        model.billState='accounted'
        if(dfType === '转预付'){
            ctx.request.body.billDate = model.billDate
            ctx.request.body.billState = 'draft'
            ctx.request.body.billType = 'YFK'
            ctx.request.body.buId = model.buId
            ctx.request.body.remark = '政策兑付生成'
            ctx.request.body.totalAmount=model.amount
            ctx.request.body.amount=model.amount
            ctx.request.body.transType=153406
            ctx.request.body.transTypeName='预付款'
            ctx.request.body.isAuto=1
            ctx.request.body.cby = user.id
            ctx.request.body.infos = [
                {
                    accId: sub.id,
                    accName: sub.name,
                    amount: model.amount,
                    remark: '政策兑付生成',
                }
            ]
            delete ctx.request.body.id
            let ret = await saveYsf(ctx)
            if(ret.stat) {
                model.yfId = ret.data.id
            }
            else {
                throw new Error('保存失败')
            }

            await toAccounted(ctx,[ret.data.id])
        }
        if(dfType === '转其他收入'){
            let acc = await db.models['category'].findOne({
                where: {
                    id: model.accId
                }
            })
            ctx.request.body.billDate = model.billDate
            ctx.request.body.billState = 'draft'
            ctx.request.body.billType = 'SR'
            ctx.request.body.buId = model.buId
            ctx.request.body.remark = '政策兑付生成'
            ctx.request.body.totalAmount=model.amount
            ctx.request.body.amount=model.amount
            ctx.request.body.transType=153401
            ctx.request.body.transTypeName='其他收入'
            ctx.request.body.isAuto=1
            ctx.request.body.cby = user.id
            ctx.request.body.infos = [
                {
                    accId: model.accId,
                    accName: acc.name,
                    amount: model.amount,
                    remark: '政策兑付生成',
                    subjectId: sub.id,
                    subjectName: sub.fullName,
                }
            ]
            delete ctx.request.body.id
            let ret = await saveSrZc(ctx)
            if(ret.stat) {
                model.yfId = ret.data.id
            }
            else {
                throw new Error('保存失败')
            }
            await toAccounted(ctx,[ret.data.id])
        }
        await model.save()
        let list = await db.query(`select * from send_df_detail where sendDfId=${model.id}`,{type: QueryTypes.SELECT})

        let logs = Object.assign(model, {infos: list})
        let logModel = db.models['sendDfLog'].build()
        logModel.tenantId = tenantId
        logModel.type = '新增'
        logModel.content = JSON.stringify(logs)
        logModel.cby = user.id
        logModel.createdAt = tools.getTime()
        await logModel.save()
    })
    return ctx.suc('保存并审核成功')
})

router.post('zd/copyBill', async ctx => {
    let user = ctx.user
    let body = ctx.request.body
    let tenantId = user.tenantId;
    let id = body.id;
    let billNo = await setBillNo(tenantId, 150601)
    let billDate = tools.getDay()
    let invoice = await db.models['invoice'].findOne({
        where: {
            tenantId,
            id
        }
    })
    if(invoice) {
        invoice.billState = 'draft'
        invoice.billDate = billDate
        invoice.billNo = billNo
        invoice.orgin = 'zd'
        invoice.createdAt = tools.getTime()
        let infos = await db.query(`select * from v_main_info where tenantId=${tenantId} and iid=${id} `,{type: QueryTypes.SELECT})
        await db.transaction(async () => {
            await invoice.save()
            infos.map(row => {
                row.iid = invoice.id
                delete row.id
            })
            await db.models['invoiceInfos'].bulkCreate(infos)
        })
        return ctx.suc('下单成功', invoice)
    }
    return ctx.err('查询失败')
})
// 保存采购
const savePurSale = async (ctx) => {
    try {
        let body = ctx.request.body
        let uid = ctx.user.id
        let user = ctx.user
        let tenantId = user.tenantId
        let infos = body.infos
        let invoiceModel = await setInvoiceModel(ctx)
        // 保存业务主要数据
        let ret = await db.transaction(async () => {
            if (body.id) {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceInfo'].destroy({
                    where: {
                        iid: invoiceModel.id,
                        tenantId
                    }
                })
            }
            else {
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            await saveDikouList(body, invoiceModel) // 保存预收，预付抵扣列表
            await saveInfos(infos, invoiceModel)

            await saveHistPrice(invoiceModel, infos)
            await saveContactSales(invoiceModel);

            //await saveContactGoods(invoiceModel);

            if(invoiceModel.transType != 150706 && invoiceModel.transType!=150806) {
                await setInvoiceGoods(tenantId, invoiceModel.id);
            }
            return invoiceModel
        })

        // 保存日志
        let obj = {...invoiceModel}
        obj.infos = infos
        //
        await tools.saveLogInvoice(tenantId, uid, ret.id, body.id ?'修改':'新增', obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
const setInvoiceModel = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let id = body.id
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let infos = ctx.request.body.infos
        let billType = body.billType
        let transTypeName = body.transTypeName
        if (!transType || !billType || !transTypeName) throw new Error('未知票据类型');
        let byCell = body.ter === 'cell' ? 1 : 0
        await updateAssQty(ctx)
        let invoiceModel = null
        // 修改
        if (id) {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) throw new Error('未找到票据或者已被删除');
            if (invoiceModel.isInit) throw new Error("不能修改期初数据");
            if (invoiceModel.billState === 'del') throw new Error("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') throw new Error("不能修改已审核数据");
        }
        // 新增
        else {
            invoiceModel = db.models['invoice'].build()
            invoiceModel.byCell = byCell;
            invoiceModel.billNo = await setBillNo(tenantId, transType)
            invoiceModel.orgin = body.orgin?body.orgin:'';
        }
        if (body.accId) {
            if (!body.rpAmount) throw new Error('请输入账户金额');
        }
        if (!invoiceModel.billNo)throw new Error("没有票据号");
        let deliverIds = body.deliverIds ? (body.deliverIds === '[]' ? "" : body.deliverIds) : ""
        let deliverNames = body.deliverNames ? body.deliverNames : ''
        if (deliverIds) {
            if (deliverIds === '0') deliverIds = "";
            if (deliverIds.indexOf("0,") === 0) {
                deliverIds = deliverIds.substring(2);
            }
            if (deliverIds.indexOf("NaN,") === 0) {
                deliverIds = deliverIds.substring(4);
            }
        }
        let yhAmount = 0; // 收付款优惠总金额
        invoiceModel.billState = 'draft'
        invoiceModel.tenantId = tenantId
        invoiceModel.billDate = body.billDate
        invoiceModel.otherType = body.otherType?body.otherType:''
        invoiceModel.transType = body.transType
        invoiceModel.transTypeName = body.transTypeName
        invoiceModel.billType = body.billType
        invoiceModel.buId = tools.xe.toNumber(body.buId)
        if(invoiceModel.buId === 0) {
            throw Error('请选择客户');
        }
        invoiceModel.doId = tools.xe.toNumber(body.doId)
        invoiceModel.salesId = tools.xe.toNumber(body.salesId);
        invoiceModel.remark = body.remark
        invoiceModel.accId = tools.xe.toNumber(body.accId)
        invoiceModel.accId1 = tools.xe.toNumber(body.accId1)
        invoiceModel.accAmount1 = tools.xe.toNumber(body.accAmount1)
        invoiceModel.deliverIds = deliverIds;
        invoiceModel.deliverNames = deliverNames;
        invoiceModel.totalAmount = tools.xe.toNumber(body.totalAmount);
        invoiceModel.disAmount = tools.xe.toNumber(body.disAmount)
        invoiceModel.amount = tools.minus(body.totalAmount, body.disAmount)
        invoiceModel.ysAmount = tools.xe.toNumber(body.ysAmount)
        invoiceModel.rpAmount = tools.xe.toNumber(body.rpAmount);
        invoiceModel.arrears = tools.xe.toNumber(body.arrears);
        invoiceModel.hxAmount = tools.xe.toNumber(body.ysAmount) // 有预收，预付表示核销金额
        invoiceModel.yhAmount = yhAmount;
        valid(body, invoiceModel, infos)
        invoiceModel.accAmount = invoiceModel.rpAmount;
        invoiceModel.leftAmount = tools.minus(invoiceModel.amount,invoiceModel.rpAmount, invoiceModel.hxAmount,invoiceModel.yhAmount)
        if(invoiceModel.transType === 150601) {
            if(!invoiceModel.salesId) {
                throw Error('请选择业务员');
            }
        }

        return invoiceModel
    }
    catch (e) {
        throw new Error(e)
    }
}
// 设置主表的 goods,subRemark

const valid = (body, invoiceModel, infos) => {
    let totalDiscount = 0
    let calAmount = 0
    let totalAmount = tools.xe.toNumber(body.totalAmount) // 总金额
    let ysAmount = tools.xe.toNumber(body.ysAmount) // 预收/预付
    let disAmount = tools.xe.toNumber(body.disAmount) // 票据优惠
    let rpAmount = tools.xe.toNumber(body.rpAmount) // 收/付款金额
    for (let i = 0; i < infos.length; i++) {
        let invoiceInfo = infos[i]
        if (!invoiceInfo.invId) continue;
        let subAmount = tools.xe.toNumber(invoiceInfo.amount)
        let price = tools.xe.toNumber(invoiceInfo.price)
        let qty = tools.xe.toNumber(invoiceInfo.qty)
        let deduction = tools.xe.toNumber(invoiceInfo.deduction)
        if (qty === 0) throw Error('数量不能等于 0 ')
        let p = qty !== 0 ? tool.xe.round((tool.xe.add(tool.xe.divide(subAmount,qty), deduction)),2) : 0
        if(tool.xe.round(price, 2) !== p)
            throw Error(invoiceInfo.invName + "  金额不等于 数量 * 单价");
        totalDiscount = tools.add(totalDiscount, tools.multiply(qty, invoiceInfo.deduction))
        let calNum = tools.xe.toNumber(invoiceInfo.calNum)
        let detail = tools.multiply(invoiceInfo.qty, calNum)

        invoiceInfo.send = invoiceInfo.send?tool.xe.trim(invoiceInfo.send):''
        invoiceInfo.remark = invoiceInfo.remark?tool.xe.trim(invoiceInfo.remark):''

        if(invoiceModel.transType === 150601) {
            if(!invoiceInfo.price) {
                if(!invoiceInfo.send && !invoiceInfo.remark) {
                    throw Error('单价为 0 必须要有备注 或 选择赠品')
                }
            }
        }
        // 最小单位不能有小数
        if (tools.xe.isFloat(detail)) throw Error(invoiceInfo.invName + "  最小单位数量不能为小数");
        let amount = tools.xe.toNumber(invoiceInfo.amount)
        if(invoiceModel.transType === 150603) {
            if(invoiceInfo.trans === '换入') amount = -amount
        }
        calAmount = tools.add(calAmount, amount)
    }
    let arrears = tools.minus(calAmount, rpAmount, disAmount, ysAmount); // 本次欠款
    if(totalAmount !== calAmount) {
        throw Error('合计金额有误')
    }
    if(invoiceModel.billType === 'OO' || invoiceModel.billType === 'OI') {
        invoiceModel.arrears = invoiceModel.totalAmount
        invoiceModel.amount = invoiceModel.totalAmount
    }
    if(tools.xe.toNumber(invoiceModel.arrears) !== arrears) {
        throw Error('合计金额错误')
    }
    let ysam = 0
    if (body.dikouList && body.dikouList.length > 0) {
        body.dikouList.map(row => {
            ysam = tools.add(ysam, row.hxAmount)
        })
        if (ysam !== tools.xe.toNumber(body.ysAmount)) {
            throw Error('抵扣金额不等于选择票据核销金额之和')
        }
    }
    invoiceModel.totalDiscount = totalDiscount;
}
const saveDikouList = async (body, invoiceModel) => {
    if (invoiceModel.transType === 150501 || invoiceModel.transType === 150601) {
        await db.models['invoiceDikou'].destroy({
            where: {
                tenantId: invoiceModel.tenantId,
                iid: invoiceModel.id
            }
        })
    }
    if (invoiceModel.transType === 150501 || invoiceModel.transType === 150601) {
        if (body.dikouList && body.dikouList.length > 0) {
            let dikou = []
            body.dikouList.map(row => {
                dikou.push({
                    iid: invoiceModel.id,
                    tenantId: invoiceModel.tenantId,
                    relId: row.relId,
                    hxAmount: row.hxAmount
                })
            })
            await db.models['invoiceDikou'].bulkCreate(dikou)
        }
    }
}
const saveInfos = async (infos, invoiceModel) => {
   //
    let arr = []
    let unitM = await tools.getUnits()
    let invs = []
    for (let i = 0; i < infos.length; i++) {
        if(!infos[i].invId) {
            continue
        }
        let unitId = null;
        unitM.map(row => {
            if(row.name === infos[i].unit) {
                unitId = row.id
            }
        })
        invs.push(`select ${infos[i].invId} invId,'${infos[i].unit}' unit `)
        if(!unitId) throw new Error('商品计量单位关联失败')
        arr.push({
            iid: invoiceModel.id,
            billNo: invoiceModel.billNo,
            tenantId: invoiceModel.tenantId,
            locationId: infos[i].locationId,
            locationName: infos[i].locationName,
            invId: infos[i].invId,
            invName: infos[i].invName,
            spec: infos[i].spec,
            calNum: infos[i].calNum,
            unit: infos[i].unit,
            unitId: unitId,
            qty: tools.xe.toNumber(infos[i].qty),
            price: tools.xe.toNumber(infos[i].price),
            deduction: tools.xe.toNumber(infos[i].deduction),
            amount: tools.xe.toNumber(infos[i].amount),
            send: infos[i].send,
            sendId: tools.xe.toNumber(infos[i].sendId),
            ysId: tools.xe.toNumber(infos[i].ysId),
            remark: infos[i].remark,
            srcOrderNo: infos[i].srcOrderNo,
            trans: infos[i].trans?infos[i].trans:'',
            transType: invoiceModel.transType,
            isYs: tools.xe.toNumber(infos[i].isYs),
        })
    }
    // let sql = `SELECT tenantId ,name,id,isnull(unit1,'') unit1,isnull(unit2,'') unit2 from goods where tenantId=${invoiceModel.tenantId} `
    // let invsSql = `select a.invId,a.unit,b.unit1,b.unit2,b.name from (${invs.join(' union all ')}) a left join (${sql}) b on a.invId=b.id `
    // let invArr = await db.query(invsSql,{type: QueryTypes.SELECT})
    // for (let i = 0; i <invArr.length ; i++) {
    //     if(invArr[i].unit !== invArr[i].unit1 && invArr[i].unit !== invArr[i].unit2) {
    //         throw new Error(`${invArr[i].name} 没有单位 ${invArr[i].unit}`)
    //     }
    // }
    //
    await db.models['invoiceInfo'].bulkCreate(arr)

}
// 保存预收商品
const saveYsg = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let infos = body.infos
        let id = body.id
        let buId = tools.xe.toNumber(body.buId)
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let billType = body.billType
        let transTypeName = body.transTypeName
        let totalAmount = tools.xe.toNumber(body.totalAmount)
        let isAdd = id ? false : true
        if(transType !== 160001) {
            if (buId === 0) return ctx.err("请选择客户");
        }
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let byCell = body.ter === 'cell' ? 1 : 0
        let billDate = body.billDate
        let invoiceModel = null
        let accId = tools.xe.toNumber(body.accId)
        let accId1 = tools.xe.toNumber(body.accId1)
        let accAmount = tools.xe.toNumber(body.accAmount)
        let accAmount1 = tools.xe.toNumber(body.accAmount1)
        // 修改
        if (isAdd) {
            invoiceModel = db.models['invoice'].build()
        }
        else {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        if (totalAmount === 0) return ctx.err("请输入预收金额");
        let unitM = await tools.getUnits()
        //
        for (let i = 0; i < infos.length; i++) {
            let invoiceInfoYs = infos[i]
            if (!invoiceInfoYs.invId) continue
            invoiceInfoYs.tenantId = tenantId
            let unitId = null;
            unitM.map(row => {
                if(row.name === invoiceInfoYs.unit) {
                    unitId = row.id
                }
            })
            if(!unitId) throw new Error('计量单位关联失败')
            invoiceInfoYs.unitId = unitId
            let subAmount = tools.xe.toNumber(invoiceInfoYs.amount)
            let price = tools.xe.toNumber(invoiceInfoYs.price)
            let qty = tools.xe.toNumber(invoiceInfoYs.qty)
            if (qty <= 0) return ctx.err('数量小于 0 ')
            // 算单价
            if (billType === 'YSG') {
                let p = qty !== 0 ? tool.xe.round((tool.xe.add(tool.xe.divide(subAmount,qty), 0)),2) : 0
                if(tool.xe.round(price, 2) !== p)
                    throw Error(invoiceInfoYs.invName + "  金额不等于 数量 * 单价");

            }
            let calNum = tools.xe.toNumber(invoiceInfoYs.calNum)
            let detail = tools.multiply(invoiceInfoYs.qty, calNum)
            // 最小单位不能有小数
            if (detail.toString().indexOf('.') !== -1) {
                return ctx.err(invoiceInfoYs.invName + "  最小单位数量不能为小数");
            }
        }
        let calAmount = tools.xe.sum(infos, 'amount')
        if(totalAmount !== calAmount) return ctx.err('合计金额错误')
        let amountAll = tools.add(accAmount, accAmount1)
        if(totalAmount!== amountAll) return ctx.err('收款账户合计金额不等于商品合计金额')
        // 保存主表
        let ret = await db.transaction(async () => {
            invoiceModel.tenantId = tenantId
            invoiceModel.billState = 'draft'
            invoiceModel.billDate = billDate
            invoiceModel.byCell = byCell
            invoiceModel.billType = billType
            invoiceModel.transType = transType
            invoiceModel.transTypeName = transTypeName
            invoiceModel.buId = buId
            invoiceModel.accId = accId
            invoiceModel.accId1 = accId1
            invoiceModel.accAmount = accAmount
            invoiceModel.accAmount1 = accAmount1
            invoiceModel.doId = tools.xe.toNumber(body.doId)
            invoiceModel.salesId = tools.xe.toNumber(body.salesId)
            invoiceModel.hxAmount = 0
            invoiceModel.yhAmount = 0
            invoiceModel.totalAmount = tools.xe.toNumber(body.totalAmount)
            invoiceModel.amount = tools.xe.toNumber(body.totalAmount)
            invoiceModel.leftAmount = tools.xe.toNumber(body.totalAmount)
            invoiceModel.subRemark = body.subRemark
            if (isAdd) {
                invoiceModel.billNo = await setBillNo(tenantId, transType)
                if (!invoiceModel.billNo) return ctx.err("没有票据号");
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            else {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceInfoYs'].destroy({
                    where: {
                        tenantId,
                        iid: id
                    }
                })
            }
            if (infos.length > 0) {// 收付款可以不对应明细
                for (let i = 0; i < infos.length; i++) {
                    delete infos[i].id
                    infos[i].iid = invoiceModel.id
                    infos[i].tenantId = invoiceModel.tenantId
                }
                await db.models['invoiceInfoYs'].bulkCreate(infos)
            }

            return invoiceModel
        })
        let obj = {...invoiceModel}
        obj.infos = infos
        tools.saveLogInvoice(tenantId, uid, invoiceModel.id, op, obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
const saveTrans = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let infos = body.infos
        let id = body.id
        let buId = tools.xe.toNumber(body.buId)
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let billType = body.billType
        let transTypeName = body.transTypeName
        let isAdd = id ? false : true
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let byCell = body.ter === 'cell' ? 1 : 0
        let billDate = body.billDate
        let invoiceModel = null

        // 修改
        if (isAdd) {
            invoiceModel = db.models['invoice'].build()
        }
        else {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        //
        let totalAmount = tools.xe.sum(infos, 'amount')
        // 保存主表
        let ret = await db.transaction(async () => {
            invoiceModel.tenantId = tenantId
            invoiceModel.billState = 'draft'
            invoiceModel.billDate = billDate
            invoiceModel.byCell = byCell
            invoiceModel.billType = billType
            invoiceModel.transType = transType
            invoiceModel.transTypeName = transTypeName
            invoiceModel.doId = tools.xe.toNumber(body.doId)
            invoiceModel.hxAmount = 0
            invoiceModel.yhAmount = 0
            invoiceModel.totalAmount = totalAmount
            invoiceModel.amount = totalAmount
            invoiceModel.leftAmount = totalAmount
            invoiceModel.subRemark = body.subRemark
            if (isAdd) {
                invoiceModel.billNo = await setBillNo(tenantId, transType)
                if (!invoiceModel.billNo) return ctx.err("没有票据号");
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            else {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceTrans'].destroy({
                    where: {
                        tenantId,
                        iid: id
                    }
                })
            }

            if (infos.length > 0) {// 收付款可以不对应明细
                for (let i = 0; i < infos.length; i++) {
                    delete infos[i].id
                    infos[i].iid = invoiceModel.id
                    infos[i].tenantId = invoiceModel.tenantId
                }
                await db.models['invoiceTrans'].bulkCreate(infos)
            }

            return invoiceModel
        })
        let obj = {...invoiceModel}
        obj.infos = infos
        await tools.saveLogInvoice(tenantId, uid, ret.id, op, obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
// 其他应收应付
const saveYsYf = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let infos = body.infos
        let id = body.id
        let buId = tools.xe.toNumber(body.buId)
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let billType = body.billType
        let transTypeName = body.transTypeName
        let accId = 0 // 应收付科目
        let accName = '' // 应收付科目
        let isAdd = id ? false : true
        if (buId === 0) return ctx.err("请选择客户");
        let sub = await db.models['category'].findOne({
            where: {
                tenantId,
                typeNumber: 'subject',
                name: transTypeName
            }
        })
        if(!sub) return ctx.err('未找到对应类别')
        accId = sub.id
        accName = sub.name
        if (!accId) return ctx.err("请选择科目");
        if (!accName) return ctx.err("请选择科目");
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let byCell = body.ter === 'cell' ? 1 : 0
        let billDate = body.billDate
        let invoiceModel = null
        // 修改
        if (isAdd) {
            invoiceModel = db.models['invoice'].build()
        }
        else {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        if(infos.length === 0) return ctx.err('没有明细')
        let subRemark = []
        infos.map(row => {
            if(row.remark) subRemark.push(row.remark)
        })
        //
        let totalAmount = tools.xe.sum(infos, 'amount')
        // 保存主表
        let ret = await db.transaction(async () => {
            invoiceModel.tenantId = tenantId
            invoiceModel.billState = 'draft'
            invoiceModel.billDate = billDate
            invoiceModel.byCell = byCell
            invoiceModel.buId = buId
            invoiceModel.billType = billType
            invoiceModel.transType = transType
            invoiceModel.transTypeName = transTypeName
            invoiceModel.doId = tools.xe.toNumber(body.doId)
            invoiceModel.hxAmount = 0
            invoiceModel.yhAmount = 0
            invoiceModel.accId = accId
            invoiceModel.accAmount = totalAmount
            invoiceModel.totalAmount = totalAmount
            invoiceModel.amount = totalAmount
            invoiceModel.leftAmount = totalAmount
            invoiceModel.subRemark = subRemark.length > 0 ? subRemark.join(',') :''
            if (isAdd) {
                invoiceModel.billNo = await setBillNo(tenantId, transType)
                if (!invoiceModel.billNo) return ctx.err("没有票据号");
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            else {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceOther'].destroy({
                    where: {
                        tenantId,
                        iid: id
                    }
                })
            }
            if (infos.length > 0) {// 收付款可以不对应明细
                for (let i = 0; i < infos.length; i++) {
                    delete infos[i].id
                    infos[i].iid = invoiceModel.id
                    infos[i].tenantId = invoiceModel.tenantId
                }
                await db.models['invoiceOther'].bulkCreate(infos)
            }

            return invoiceModel
        })
        let obj = {...invoiceModel}
        obj.infos = infos
        tools.saveLogInvoice(tenantId, uid, ret.id, op, obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
const saveReceiptPayment = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let infos = body.infos
        let id = body.id
        let buId = tools.xe.toNumber(body.buId)
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let billType = body.billType
        let transTypeName = body.transTypeName
        let isAdd = id ? false : true
        let os = transType === 153001 ? "客户" : "供应商";
        if (buId === 0) return ctx.err("请选择"+os);
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let invoiceModel = db.models['invoice'].build()
        let subRemark = []
        // 修改
        if (!isAdd) {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        let amount = tools.xe.toNumber(body.amount) // 收款总金额，不包含收款优惠的金额
        let yhAmount = 0
        if(infos && infos.length > 0) {
            for (let i = 0; i < infos.length; i++) {
                yhAmount = tools.add(yhAmount, tools.xe.toNumber(infos[i].yhAmount))
                delete infos[i].id
                infos[i].remark && subRemark.push(infos[i].remark)
            }
        }
        let accAmount = tools.xe.toNumber(body.accAmount)
        let accAmount1 = tools.xe.toNumber(body.accAmount1)
        if(amount !== tools.xe.add(accAmount, accAmount1)) {
            return ctx.err('账户合计金额不等于总金额');
        }
        // 保存主表
        let ret = await db.transaction(async () => {
            invoiceModel.tenantId = tenantId
            invoiceModel.billState = 'draft'
            invoiceModel.billDate = body.billDate
            invoiceModel.byCell = body.byCell
            invoiceModel.byScan = body.byScan?body.byScan:0
            invoiceModel.accId = tools.xe.toNumber(body.accId)
            invoiceModel.accId1 = tools.xe.toNumber(body.accId1)
            invoiceModel.accAmount = accAmount
            invoiceModel.accAmount1 = accAmount1
            invoiceModel.billType = body.billType
            invoiceModel.transType = body.transType
            invoiceModel.transTypeName = body.transTypeName
            invoiceModel.buId = body.buId
            invoiceModel.salesId = body.salesId
            invoiceModel.totalAmount = tools.add(amount, yhAmount)
            invoiceModel.yhAmount = yhAmount
            invoiceModel.disAmount = yhAmount
            invoiceModel.amount = amount
            invoiceModel.leftAmount = amount
            invoiceModel.subRemark = subRemark.length > 0 ? subRemark.join(',') : ''
            if (isAdd) {
                invoiceModel.billNo = await setBillNo(tenantId, transType)
                if (!invoiceModel.billNo) return ctx.err("没有票据号");
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            else {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceReceipt'].destroy({
                    where: {
                        tenantId,
                        iid: id
                    }
                })
            }
            if (infos.length > 0) {// 收付款可以不对应明细
                for (let i = 0; i < infos.length; i++) {
                    delete infos[i].id
                    infos[i].iid = invoiceModel.id
                    infos[i].tenantId = invoiceModel.tenantId
                    infos[i].nowCheck = tools.xe.toNumber(infos[i].nowCheck)
                    infos[i].yhAmount = tools.xe.toNumber(infos[i].yhAmount)
                    infos[i].hxAmount = tools.xe.toNumber(infos[i].hxAmount)
                    infos[i].leftAmount = tools.xe.toNumber(infos[i].leftAmount)
                    infos[i].arrears = tools.xe.toNumber(infos[i].arrears)
                }
                await db.models['invoiceReceipt'].bulkCreate(infos)
            }

            return invoiceModel
        })
        let obj = {...invoiceModel}
        obj.infos = infos
        await tools.saveLogInvoice(tenantId, uid, ret.id, op, obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
// 其他收入 支出
const saveSrZc = async (ctx) => {
    try {
        let body = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let infos = body.infos
        let id = body.id
        let buId = tools.xe.toNumber(body.buId)
        let salesId = tools.xe.toNumber(body.salesId)
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(body.transType)
        let billType = body.billType
        let transTypeName = body.transTypeName
        let isAdd = id ? false : true
        let isAuto = body.isAuto?body.isAuto:0
        let os = transType === 153401 ? "客户" : "供应商";
        if (buId === 0) return ctx.err("请选择"+os);
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let byCell = body.ter === 'cell' ? 1 : 0
        let billDate = body.billDate
        let invoiceModel = db.models['invoice'].build()
        // 修改
        if (!isAdd) {
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        if(infos && infos.length > 0) {
            for (let i = 0; i < infos.length; i++) {
                delete infos[i].id
            }
        }
        // 保存主表
        let ret = await db.transaction(async () => {
            invoiceModel.tenantId = tenantId
            invoiceModel.billState = 'draft'
            invoiceModel.billDate = billDate
            invoiceModel.byCell = byCell
            invoiceModel.billType = billType
            invoiceModel.transType = transType
            invoiceModel.transTypeName = transTypeName
            invoiceModel.buId = buId
            invoiceModel.salesId = salesId
            invoiceModel.totalAmount = body.totalAmount
            invoiceModel.amount = body.totalAmount
            invoiceModel.leftAmount = body.totalAmount
            invoiceModel.subRemark = body.subRemark
            invoiceModel.remark = body.remark
            invoiceModel.isAuto = isAuto
            if (isAdd) {
                invoiceModel.billNo = await setBillNo(tenantId, transType)
                if (!invoiceModel.billNo) return ctx.err("没有票据号");
                invoiceModel.cby = uid
                invoiceModel.createdAt = tools.getTime()
                await invoiceModel.save()
            }
            else {
                invoiceModel.updatedAt = tools.getTime()
                await invoiceModel.save()
                await db.models['invoiceOther'].destroy({
                    where: {
                        tenantId,
                        iid: id
                    }
                })
            }
            if (infos.length > 0) {// 收付款可以不对应明细
                for (let i = 0; i < infos.length; i++) {
                    delete infos[i].id
                    infos[i].iid = invoiceModel.id
                    infos[i].tenantId = invoiceModel.tenantId
                    infos[i].amount = tools.xe.toNumber(infos[i].amount)
                }
                await db.models['invoiceOther'].bulkCreate(infos)
            }

            return invoiceModel
        })
        let obj = {...invoiceModel}
        obj.infos = infos
        tools.saveLogInvoice(tenantId, uid, ret.id, op, obj);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
// 保存 预收 预付
const saveYsf = async (ctx) => {
    let user = ctx.user
    let body = ctx.request.body
    let tenantId = user.tenantId;
    let buId = body.buId
    let doId = body.doId
    let salesId = body.salesId
    let billDate = body.billDate
    let cby = body.cby
    let remark = body.remark
    let transType = body.transType
    if(!buId) return ctx.err('请选择往来单位')
    let infos = body.infos
    let amount = 0
    let isAuto = body.isAuto?body.isAuto:0
    let arr = []
    let subject = await db.models['category'].findOne({
        where: {
            tenantId,
            name: transType === 153407?'预收账款':'预付账款'
        }
    })
    let subRemark = []
    infos.map(row => {
        if(row.accId) {
            amount = tools.add(row.amount, amount)
            row.subjectId = subject.id
            row.subjectName = transType === 153407?'预收账款':'预付账款'
            arr.push(row)
            if(row.remark) {
                subRemark.push(row.remark)
            }
        }
    })
    delete body.infos
    if(arr.length > 0) {
        if(body.id) {
            arr.map(row => {
                row.tenantId = tenantId
                row.iid = body.id
            })
            let updatedAt = tools.getTime()
            let model = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: body.id,
                }
            })
            model.buId = buId
            model.doId = doId
            model.salesId = salesId
            model.updatedAt = updatedAt
            model.remark = remark
            model.totalAmount = amount
            model.amount = amount
            model.rpAmount = amount
            model.leftAmount = amount
            model.billState =  'draft'
            model.arrears = 0
            model.isAuto = isAuto
            model.subRemark = subRemark.length>0?subRemark.join(','):''
            let res = await db.transaction(async () => {
                await model.save()
                await db.models['invoiceOther'].destroy({
                    where: {
                        tenantId,
                        iid: body.id
                    }
                })
                await db.models['invoiceOther'].bulkCreate(arr)
                return model
            })
            return ctx.suc('保存成功 ', res)
        }
        else {
            let createdAt = tools.getTime()
            let billNo = await setBillNo(tenantId, transType)
            let model = {
                transTypeName: body.transTypeName,
                transType: body.transType,
                billType: body.billType,
                billState: 'draft',
                totalAmount: amount,
                amount: amount,
                leftAmount: amount,
                rpAmount: amount,
                arrears: 0,
                isAuto,
                remark,
                subRemark: subRemark.length>0?subRemark.join(','):'',
                billNo,
                tenantId,
                buId,
                doId,
                billDate,
                cby,
                createdAt
            }
            let res = await db.transaction(async () => {
                let ret = await db.models['invoice'].create(model)
                arr.map(row => {
                    row.tenantId = tenantId
                    row.iid = ret.id
                })
                await db.models['invoiceOther'].bulkCreate(arr)
                return ret
            })
            return ctx.suc('保存成功 ', res)
        }
    }
    else {
        return ctx.err('请完善数据')
    }
}
// 保存凭证
const saveCard = async (ctx) => {
    try {
        let user = ctx.user
        let tenantId = user.tenantId;
        let body = ctx.request.body
        let uid = user.id;
        let ctime = tools.getTime()
        let billDate = body.billDate;
        let roleId = user.roleId;
        let roleName = user.roleName;
        let op = '修改';
        let cardInfos = body.infos;
        let buId = body.buId ? body.buId : 0;
        let buName = body.buName ? body.buName : '';
        let cardModel = {
            billType: 'PZ',
            transType: 190001,
            transTypeName: '凭证',
            tenantId,
            billYear: billDate.substring(0, 4),
            billMonth: billDate.substring(5, 7),
            buId,
            buName,
            billDate: billDate,
            billState: 'draft'
        }
        if(buName) {
            if(buId == 0) {
                throw Error('往来单位不能为空')
            }
        }
        if (!body.id) {
            op = '新增';
            cardModel.createdAt = ctime;
            cardModel.cby = uid;
        }
        else {
            cardModel.updatedAt = ctime;
            cardModel.updatedBy = uid;
            let cd = await db.models['card'].findOne({
                where: {
                    id: body.id,
                    tenantId
                }
            })
            if (!cd) {
                throw Error('未找到票据')
            }
            if (cd.billState != 'draft') {
                throw Error('不能修改非草稿数据')
            }
        }
        if (cardInfos.length < 2) {
            throw Error('至少 2 条分录');
        }
        let p1 = 0
        let p2 = 0
        for (let it in cardInfos) {
            p1 = tools.add(it.price1, p1)
            p2 = tools.add(it.price2, p2)
        }
        if (p1 !== p2) {
            throw Error('借贷不相等');
        }
        if (!body.id) {
            cardModel.billNo = await setBillNo(tenantId, 190001)
        } else {
            cardModel.billNo = body.billNo;
        }
        let model = await db.transaction(async () => {
            if (body.id) {
                await db.models['cardInfo'].destroy({
                    where: {
                        tenantId,
                        cardId: body.id
                    }
                })
                cardModel.id = body.id;
                await db.models['card'].update(cardModel, {
                    where: {
                        tenantId,
                        id: body.id
                    }
                })
            }
            else {
                let cm = await db.models['card'].create(cardModel)
                body.id = cm.id
                cardModel.id = body.id;
            }
            let cinfo = []
            for (let i = 0; i < cardInfos.length; i++) {
                let it = cardInfos[i]
                let category = await db.models['category'].findOne({
                    where: {
                        id: it.subjectId
                    }
                })
                let info = {
                    tenantId,
                    cardId: body.id,
                    billNo: cardModel.billNo,
                    buId,
                    buName,
                    subjectId: category.id,
                    subjectName: category.name,
                    subjectCode: category.code,
                    price1: it.price1,
                    price2: it.price2,
                    remark: it.remark,
                    fullName: category.fullName
                }
                cinfo.push(info)
            }
            await db.models['cardInfo'].bulkCreate(cinfo)
            return cardModel
        })
        return ctx.suc("已保存", model);
    } catch (e) {
        throw Error(e);
    }
}
// 检测数据


module.exports = router;